package org.goldenport.g3

import org.goldenport.application.GApplicationDescriptor
import UAgent._
import org.goldenport.Goldenport
import org.goldenport.g3.messages.Get
import org.goldenport.g3.messages.Post
import org.goldenport.g3.messages.Put
import org.goldenport.g3.messages.Delete
import org.goldenport.g3.messages.RestCommand
import org.goldenport.g3.adapters.GoldenportDriver

/**
 * @since   Nov. 28, 2011
 * @version Nov. 29, 2011
 * @author  ASAMI, Tomoharu
 */
abstract class G3Action {
  def isDefinedAt(in: AnyRef): Boolean
  def apply(ctx: G3AgentContext, in: AnyRef): AnyRef
}

class PartialFunctionAction(val pf: PartialFunction[_, _]) extends G3Action {
  val pfo = pf.asInstanceOf[PartialFunction[AnyRef, AnyRef]]
  def isDefinedAt(in: AnyRef) = pfo.isDefinedAt(in)
  def apply(ctx: G3AgentContext, in: AnyRef) = pfo.apply(in)
}

class FunctionAction(val f: Function1[_, _]) extends G3Action {
  val fo = f.asInstanceOf[Function1[AnyRef, AnyRef]]

  def isDefinedAt(in: AnyRef) = {
    isValidFunction(fo, in)
  }

  def apply(ctx: G3AgentContext, in: AnyRef) = {
    fo.apply(in)
  }
}

class ObjectAction(val o: AnyRef) extends G3Action {
  def isDefinedAt(in: AnyRef) = {
    findMethodOfObject(o, in).isDefined
  }

  def apply(ctx: G3AgentContext, in: AnyRef) = {
    findMethodOfObject(o, in).get.invoke(o, in)
  }
}

class ClassAction(val c: Class[_]) extends G3Action {
  def isDefinedAt(in: AnyRef) = {
    findMethodOfClass(c, in).isDefined
  }

  def apply(ctx: G3AgentContext, in: AnyRef) = {
    val o = c.newInstance()
    findMethodOfClass(c, in).get.invoke(o, in)
  }
}

class GoldenportAction(val context: G3Context, val desc: GApplicationDescriptor) extends G3Action {
  private val _goldenport = new Goldenport(Array(), desc)
  _goldenport.open()
  private val _driver = new GoldenportDriver(_goldenport)
  _driver.open(context)

  def isDefinedAt(in: AnyRef) = {
    in match {
      case get: Get => _can_get(get)
      case post: Post => _can_post(post)
      case put: Put => _can_put(put)
      case delete: Delete => _can_delete(delete)
      case _ => false
    }
  }

  def apply(ctx: G3AgentContext, in: AnyRef) = {
    in match {
      case get: Get => _apply_get(ctx, get)
      case post: Post => _apply_post(ctx, post)
      case put: Put => _apply_put(ctx, put)
      case delete: Delete => _apply_delete(ctx, delete)
      case _ => in //
    }
  }

  private def _can_get(get: Get) = {
    val (service, args, params) = get.asOperation
    _goldenport.isAccept(service, args, params)
  }

  private def _can_post(post: Post) = {
    val (service, args, params) = post.asOperation
    _goldenport.isAccept(service, args, params)
  }

  private def _can_put(put: Put) = {
    val (service, args, params) = put.asOperation
    _goldenport.isAccept(service, args, params)
  }

  private def _can_delete(delete: Delete) = {
    val (service, args, params) = delete.asOperation
    _goldenport.isAccept(service, args, params)
  }

  private def _apply_get(ctx: G3AgentContext, get: Get) = {
    _driver.execute(get, ctx)
  }

  private def _apply_post(ctx: G3AgentContext, post: Post) = {
    _driver.execute(post, ctx)    
  }

  private def _apply_put(ctx: G3AgentContext, put: Put) = {
    _driver.execute(put, ctx)    
  }

  private def _apply_delete(ctx: G3AgentContext, delete: Delete) = {
    _driver.execute(delete, ctx)    
  }
}
